import { isObj } from './tools'
class MyPromise {
  constructor(func) {
    this.status = 'pending'
    this.onResolvedCbs = []
    this.onRejectedCbs = []
    try {
      func(this.resolve.call(this), this.reject.call(this))
    } catch (err) {
      this.reject(err)
    }
  }
  resolve(value) {
    if (this.status === 'pending') {
      this.status = 'resolved'
      this.value = value
    }
  }
  reject(reason) {
    if (this.status === 'pending') {
      this.status = 'rejected'
      this.reason = reason
    }
  }
  then(onResolved, onRejected) {
    const p1 = new Promise((resolve, reject) => {
      if (this.status === 'pending') {
        this.onResolvedCbs.push(() => {
          setTimeout(() => {
            try {
              if (typeof onResolved !== 'function') {
                resolve(onResolved)
                return
              }
              const x = onResolved(this.value)
              this.resolvePromise(x, p1, resolve, reject)
            } catch (err) {
              reject(err)
            }
          })
        })
        this.onRejectedCbs.push(() => {
          try {
            if (typeof onRejected !== 'function') {
              reject(onRejected)
              return
            }
            onRejected(this.reason)
          } catch (err) {
            reject(err)
          }
        })
      }
      if (this.status === 'resolved') {
        for (const fn of this.onResolvedCbs) {
          fn()
        }
      }
      if (this.status === 'rejected') {
        for (const fn of this.onRejectedCbs) {
          fn()
        }
      }
    })
    return p1
  }
  resolvePromise(x, promise2, resolve, reject) {
    if (x === promise2) {
      // 抛出错误后下面还会执行吗，不会
      throw TypeError('hahah 错了吧')
    }
    if (x instanceof Promise) {
      x.then(resolve, reject)
      return
    }
    if (isObj(x) || typeof x === 'function') {
      let call = false
      try {
        const then = x.then
        if (typeof then !== 'function') {
          if (call) return
          resolve(then)
          call = true
          return
        }
        then((y) => {
          if (call) return
          this.resolvePromise(y, promise2, resolve, reject)
          call = true
        }, reject)
      } catch (err) {
        if (call) return
        reject(err)
        call = true
      }
      return
    }
    resolve(x)
  }
}
